package export

import (
	"fmt"
	"game/game-design/loader"
	"sort"
	"strings"
)

// <类名，语言表结构>
var LANGUAGES map[string]*LanguageCollectingTable = make(map[string]*LanguageCollectingTable, 100)

func CollectLanguage(designFile *loader.DesignFile) {
	if len(designFile.Langs) <= 0 {
		return
	}
	table := NewLanguageCollectingTable(designFile)
	LANGUAGES[table.className] = table
}

// 生成语言表
func GenLanguageFile(designIO IDesignIO, exportArgs *ExportArgs) *loader.DesignFile {
	fileFullPath := exportArgs.SourceHome + exportArgs.LanguageFile
	designFiles, err := designIO.Read(fileFullPath, exportArgs.DesignDefine)
	var langFile *loader.DesignFile
	if err == nil {
		langFile = designFiles[0]
	}
	designDefine := exportArgs.DesignDefine

	if langFile == nil {
		macros := make([]string, 2)
		macros[0] = "#name " + exportArgs.LanguageClass
		macros[1] = "#index langId"

		names := make([]string, 2)
		types := make([]string, 2)
		tags := make([]string, 2)
		comments := make([]string, 2)

		names[0] = "langId"
		types[0] = "string"
		tags[0] = designDefine.BothTag
		comments[0] = "语言ID"

		names[1] = "ori"
		types[1] = "string"
		tags[1] = designDefine.BothTag
		comments[1] = "原始文本"

		//按文件名进行排序
		fileSorts := make([]string, 0, 100)
		for key := range LANGUAGES {
			fileSorts = append(fileSorts, key)
		}
		sort.Strings(fileSorts)

		var index int = 1
		mergeIdx := make(map[string]int)

		for _, key := range fileSorts {
			table := LANGUAGES[key]

			for _, mergeSuffix := range table.mergeSuffixs {
				_, ok := mergeIdx[mergeSuffix]
				if ok {
					continue
				}
				index += 1
				mergeIdx[mergeSuffix] = index

				names = append(names, "ori"+mergeSuffix)
				types = append(types, "string")
				tags = append(tags, designDefine.BothTag)
				comments = append(comments, "原始文本"+mergeSuffix)
			}
		}

		rowDatas := make([][]string, 0, 1000)
		for _, key := range fileSorts {
			table := LANGUAGES[key]

			for _, langKey := range table.keySorts {
				rowData := table.rows[langKey]

				result := make([]string, index+1)
				result[0] = rowData.key
				result[1] = rowData.value
				for suffix, mergeData := range rowData.mergeDatas {
					idx := mergeIdx[suffix]
					result[idx] = mergeData
				}
				rowDatas = append(rowDatas, result)
			}
		}

		langFile = new(loader.DesignFile)
		langFile.Name = exportArgs.LanguageClass
		langFile.DesignDefine = designDefine
		langFile.FillMacro(macros)
		// langFile.FillField(names, types, tags, comments)
		// langFile.FillData(rowDatas)
		langFile.FillFieldAndData(names, types, tags, comments, rowDatas)

		langFile.OutputNameType = "useFileName"
		designIO.Write(langFile, exportArgs.SourceHome, designDefine.BothTag)
	} else {
		//从表里读出来的语言数据

		currTable := NewLanguageCurrTable(langFile)

		if exportArgs.Mode == "fast" {
			needToUpdate := checkRepeatKeyAndDif(langFile.Fields, currTable)
			if !needToUpdate {
				fmt.Println("语言表没有变化，不重新导出")
				return langFile
			}
			//快速模式下应该以原文件中的语言数据为基础
			fastFillLanguageFile(langFile, currTable, exportArgs)
		} else {
			needToUpdate := false
			if len(LANGUAGES) != len(currTable.groups) {
				//文件分组数不相等，表示有新的表
				needToUpdate = true
			} else {
				needToUpdate = checkRepeatKeyAndDif(langFile.Fields, currTable)
			}
			if !needToUpdate {
				fmt.Println("语言表没有变化，不重新导出")
				return langFile
			}
			fullFillLanguageFile(langFile, currTable, exportArgs)
		}
		langFile.OutputNameType = "useFileName"
		designIO.Write(langFile, exportArgs.SourceHome, designDefine.BothTag)
	}
	return langFile
}

// 检查是否有重复的语言键和数据是否有差异
func checkRepeatKeyAndDif(fields []*loader.DesignField, table *LanguageCurrTable) bool {
	hasDif := false
	repeatedKeys := make(map[string]bool)

OUTER:
	for _, collectingTable := range LANGUAGES {
		currGroup, ok := table.groups[collectingTable.className]
		if !ok {
			hasDif = true
			break OUTER
		}
		for _, key := range collectingTable.keySorts {
			_, ok := repeatedKeys[key]
			if ok {
				fmt.Println("发现重复的语言主键", key)
			}
			repeatedKeys[key] = true

			currRow, ok := currGroup.rows[key]
			if !ok {
				hasDif = true
				break OUTER
			}
			newRow := collectingTable.rows[key]
			if newRow.value != currRow.langValue {
				hasDif = true
				break OUTER
			}
			for _, mergeSuffix := range collectingTable.mergeSuffixs {
				mergeName := fields[1].Name() + mergeSuffix
				idx, ok := table.fieldIdx[mergeName]
				if !ok {
					//当前表格中未包含该合并列，则表示有变化
					hasDif = true
					break OUTER
				} else {
					//当前表格中包含该合并列，但该合并列的值发生了变化
					if currRow.datas[idx] != newRow.mergeDatas[mergeSuffix] {
						hasDif = true
						break OUTER
					}
				}
			}
		}
	}
	return hasDif
}

func fastFillLanguageFile(langFile *loader.DesignFile, currTable *LanguageCurrTable, exportArgs *ExportArgs) {
	fillLanguageFile(langFile, currTable, exportArgs, currTable.groups)
	langFile.FillData(currTable.fromResultData())
}

func fullFillLanguageFile(langFile *loader.DesignFile, currTable *LanguageCurrTable, exportArgs *ExportArgs) {
	allOldGroups := currTable.groups
	currTable.groups = make(map[string]*LanguageCurrGroup)
	fillLanguageFile(langFile, currTable, exportArgs, allOldGroups)
	langFile.FillData(currTable.fromResultData())
}

func fillLanguageFile(langFile *loader.DesignFile, currTable *LanguageCurrTable, exportArgs *ExportArgs, oldGroups map[string]*LanguageCurrGroup) {
	for _, collectingTable := range LANGUAGES {
		//在当前语言中对中未创建的合并列进行占位
		for _, suffix := range collectingTable.mergeSuffixs {
			_, ok := currTable.fieldIdx["ori"+suffix]
			if !ok {
				newIdx := len(currTable.fieldIdx)
				currTable.fieldIdx["ori"+suffix] = newIdx
				designDefine := exportArgs.DesignDefine
				langFile.AppendField("ori"+suffix, "string", designDefine.BothTag, "原始文本"+suffix)
			}
		}
		//对于正在收集的语言分组，一共需要多少列数据
		dataSize := len(currTable.fieldIdx)
		currOldTable, ok := oldGroups[collectingTable.className]

		//每次导出都用新的语言分组替换旧分组
		currNewGroup := LanguageCurrGroup{}
		currNewGroup.className = collectingTable.className
		currNewGroup.rows = make(map[string]*LanguageCurrRow)
		currNewGroup.keySorts = collectingTable.keySorts
		currTable.groups[currNewGroup.className] = &currNewGroup
		if ok {
			//当前语言表中存在该语言分组，需要进行对比并填充已有数据
			for _, key := range currNewGroup.keySorts {
				currOldRow, ok := currOldTable.rows[key]
				collectingRow := collectingTable.rows[key]
				if ok {
					//已有该行数据
					currNewRow := NewLanguageCurrRow(collectingRow, currTable, dataSize, currOldRow)
					currNewGroup.rows[currNewRow.langKey] = currNewRow
				} else {
					//未有该行数据
					currNewRow := NewLanguageCurrRow(collectingRow, currTable, dataSize, nil)
					currNewGroup.rows[currNewRow.langKey] = currNewRow
				}
			}
		} else {
			//当前语言表中没有该语言分组
			for _, key := range currNewGroup.keySorts {
				collectingRow := collectingTable.rows[key]

				currNewRow := NewLanguageCurrRow(collectingRow, currTable, dataSize, nil)
				currNewGroup.rows[currNewRow.langKey] = currNewRow
			}
		}
	}
}

func HandleLanguage(oriDesignFile *loader.DesignFile) *loader.DesignFile {
	names := make([]string, 0)
	forms := make([]string, 0)
	tags := make([]string, 0)
	comments := make([]string, 0)
	datas := make([][]string, 0)

	for i, field := range oriDesignFile.Fields {
		names = append(names, field.Name())
		forms = append(forms, field.Form())
		tags = append(tags, field.Tag())
		comments = append(comments, field.Comment())

		//对语言表的列进行处理
		langMeta, isLangField := oriDesignFile.Langs[field.Name()]
		if isLangField {
			names = append(names, field.Name()+"Lang")
			forms = append(forms, "string")
			if langMeta.ExportType() == "" {
				tags = append(tags, oriDesignFile.DesignDefine.BothTag)
			} else {
				tags = append(tags, langMeta.ExportType())
			}
			comments = append(comments, field.Comment())
		}

		//表格中的数据此处是一列一列填充回去的
		for j := 0; j < len(oriDesignFile.Datas); j++ {
			oriRowDatas := oriDesignFile.Datas[j]
			if len(datas) < j+1 {
				datas = append(datas, make([]string, 0))
			}
			if i >= len(oriRowDatas) {
				datas[j] = append(datas[j], "")
			} else {
				datas[j] = append(datas[j], oriRowDatas[i])
			}
			//对语言表的列进行处理
			if isLangField {
				upperName := strings.ToUpper(field.Name()[0:1]) + field.Name()[1:]

				var langPos string
				if len(oriDesignFile.Indexes) > 0 {
					langPos = oriDesignFile.GetFirstIndexValue(oriRowDatas)
				} else {
					langPos = oriRowDatas[0]
				}
				datas[j] = append(datas[j], oriDesignFile.ClassName+"_"+upperName+"_"+langPos)
			}
		}
	}

	var newDesignFile loader.DesignFile
	newDesignFile.Name = oriDesignFile.Name
	newDesignFile.DesignDefine = oriDesignFile.DesignDefine
	newDesignFile.FillMacro(oriDesignFile.Macros)
	// newDesignFile.FillField(names, forms, tags, comments)
	// newDesignFile.FillData(datas)
	newDesignFile.FillFieldAndData(names, forms, tags, comments, datas)
	return &newDesignFile
}
